/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.query.activity;

import com.google.common.collect.Lists;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.sfkj.walk.api.activity.ActivityMemberType;
import com.sfkj.walk.api.activity.ActivityType;
import com.sfkj.walk.api.query.activity.ActivityAllByPredicateQuery;
import com.sfkj.walk.api.query.activity.ActivityAllByUserQuery;
import com.sfkj.walk.api.query.activity.ActivityMemberAllByPredicateQuery;
import com.sfkj.walk.api.query.activity.ActivityOneByPredicateQuery;
import com.sfkj.walk.api.query.user.UserOneByPredicateQuery;
import com.sfkj.walk.query.user.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.axonframework.eventhandling.MetaDataConstants;
import org.axonframework.messaging.annotation.MetaDataValue;
import org.axonframework.queryhandling.QueryGateway;
import org.axonframework.queryhandling.QueryHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.QSort;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Component
public class ActivityQueryService {

  private final ActivityRepository activityRepository;
  private final ActivityMemberRepository activityMemberRepository;
  private final QueryGateway queryGateway;

    /* =================== 公用部分 =================== */

  @QueryHandler
  public Activity handle(final ActivityOneByPredicateQuery query, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
    Activity dto = transform(activityRepository.findOne(query.getPredicate()), currentUserId);
    if (Objects.isNull(dto)) {
      return null;
    }
    // 私有活动只能自己活着成员才能访问
    if (Objects.equals(dto.getActivityType(), ActivityType.PRIVATE) &&
      BooleanUtils.isNotTrue(dto.getIsMy()) && BooleanUtils.isNotTrue(dto.getIsMember())) {
      return null;
    }
    return dto;
  }

  private Activity transform(Activity activity, String currentUserId) {
    if (Objects.isNull(activity)) {
      return null;
    }

    Activity dto = new Activity();
    BeanUtils.copyProperties(activity, dto);

    User user = queryGateway.send(UserOneByPredicateQuery.buildById(activity.getCreatorId()), User.class)
      .getNow(null);
    dto.setCreator(user);
    if (Objects.isNull(currentUserId)) {
      dto.setIsMy(false);
      dto.setIsMember(false);
    } else {
      dto.setIsMy(Objects.equals(currentUserId, activity.getCreatorId()));
      dto.setIsMember(activityMemberRepository.exists(ActivityMember.buildBy(activity.getId(), currentUserId)));
    }

    return dto;
  }

  @QueryHandler
  public Iterable<ActivityMember> handle(final ActivityMemberAllByPredicateQuery query) {
    List<ActivityMember> items;
    if (Objects.nonNull(query.getPageable())) {
      Page<ActivityMember> page = activityMemberRepository.findAll(query.getPredicate(), query.getPageable());
      List<ActivityMember> dtos = page.getContent().stream().map(this::transformMember).collect(Collectors.toList());
      return new PageImpl<>(dtos, query.getPageable(), page.getTotalElements());
    }
    if (Objects.nonNull(query.getSort())) {
      items = Lists.newArrayList(activityMemberRepository.findAll(query.getPredicate(), query.getSort()));
      return items.stream().map(this::transformMember).collect(Collectors.toList());
    }

    items = Lists.newArrayList(activityMemberRepository.findAll(query.getPredicate()));
    return items.stream().map(this::transformMember).collect(Collectors.toList());
  }

  private ActivityMember transformMember(ActivityMember member) {
    if (Objects.isNull(member)) {
      return null;
    }

    ActivityMember dto = new ActivityMember();
    BeanUtils.copyProperties(member, dto);

    User user = queryGateway.send(UserOneByPredicateQuery.buildById(member.getMemberId()), User.class)
      .getNow(null);
    dto.setMember(user);

    return dto;
  }

    /* =================== 用户端部分 =================== */

  @QueryHandler
  public Iterable<Activity> handle(final ActivityAllByUserQuery query, @MetaDataValue(MetaDataConstants.CURRENT_USER_ID) String currentUserId) {
    switch (query.getType()) {
      case MY:
        return myList(query, currentUserId);
      case JOIN:
        return joinList(query, currentUserId);
      case COLLECT:
      default:
        return new PageImpl<>(Lists.newArrayList(), query.getPageable(), 0);
    }

  }

  private Iterable<Activity> myList(ActivityAllByUserQuery query, String currentUserId) {
    Pageable pageable = new PageRequest(
      query.getPageable().getPageNumber(), query.getPageable().getPageSize(),
      new QSort(QActivity.activity.createdDate.desc())
    );

    Predicate predicate = Activity.buildByCreatorId(query.getUserId(), Objects.equals(query.getUserId(), currentUserId));
    Page<Activity> page = activityRepository.findAll(predicate, pageable);
    List<Activity> dtos = page.getContent().stream().map(t -> transform(t, currentUserId)).collect(Collectors.toList());
    return new PageImpl<>(dtos, query.getPageable(), page.getTotalElements());
  }

  private Iterable<Activity> joinList(ActivityAllByUserQuery query, String currentUserId) {
    Pageable pageable = new PageRequest(
      query.getPageable().getPageNumber(), query.getPageable().getPageSize(),
      new QSort(QActivityMember.activityMember.createdDate.desc())
    );

    Page<ActivityMember> page = activityMemberRepository.findAll(ActivityMember.buildBy(query.getUserId(), ActivityMemberType.MEMBER), pageable);
    List<Activity> dtos = page.getContent().stream().map(t -> transform(activityRepository.findOne(t.getActivityId()), currentUserId)).collect(Collectors.toList());
    return new PageImpl<>(dtos, query.getPageable(), page.getTotalElements());
  }

    /* =================== 管理端部分 =================== */

  @QueryHandler
  public Iterable<Activity> handle(final ActivityAllByPredicateQuery query) {
    List<Activity> items;
    if (Objects.nonNull(query.getPageable())) {
      Page<Activity> page = activityRepository.findAll(query.getPredicate(), query.getPageable());
      List<Activity> dtos = page.getContent().stream().map(this::transform).collect(Collectors.toList());
      return new PageImpl<>(dtos, query.getPageable(), page.getTotalElements());
    }
    if (Objects.nonNull(query.getSort())) {
      items = Lists.newArrayList(activityRepository.findAll(query.getPredicate(), query.getSort()));
      return items.stream().map(this::transform).collect(Collectors.toList());
    }

    items = Lists.newArrayList(activityRepository.findAll(query.getPredicate()));
    return items.stream().map(this::transform).collect(Collectors.toList());
  }

  private Activity transform(Activity activity) {
    return transform(activity, null);
  }

}
